import requests as req
import time
import json
import hashlib
import geopy.distance
from collections import OrderedDict
import random
import socket
import sys
import os
import logging

DEBUG=False
LOGPATH="logs/"


class DataTemplate:
    __jsondata={}
    __submitnum=0
    __punchPoints=[]
    __geolations=[]
    __totaldistance=0
    _SportId=""

    def __init__(self,xh,appDevice,userid):
        self.__jsondata["startDatetime"]=self._getTime()
        self.__jsondata["subMit"]=str(self.__submitnum + 1)
        self.__jsondata["punchPoints"]=self.__getpunchPoints()
        self.__jsondata["addVersion"]="1.3.9"
        self.__jsondata["summile"]=self.__getsummile()
        self.__jsondata["appDevice"]=appDevice
        self.__jsondata["userid"]=userid
        self.__jsondata["dateFlag"]=self.__getdateFlag()
        self.__jsondata["avgSpeed"]=self._getavgSpeed()
        self.__jsondata["geolations"]=self.__getgeolations()
        self.__jsondata["unqualified"]=0
        self.__jsondata["total"]=self._gettotal()
        self.__jsondata["stepNumber"]=self.__getstepNumber()
        self.__jsondata["userType"]="student"
        self.__jsondata["id"]=str(xh)+"-"+str(self.__jsondata["startDatetime"])
        self.__jsondata["updatetime"]=0
        self.__jsondata["pointNum"]=len(self.__punchPoints)
        self.__jsondata["endDatetime"]=0
        self.__jsondata["key"]=self.__getkey()
        self._SportId=self.__jsondata["id"]

    def __refreshjson(self):
        self.__jsondata["subMit"]=str(self.__submitnum) 
        self.__jsondata["punchPoints"]=self.__getpunchPoints()
        self.__jsondata["summile"]=self.__getsummile()
        self.__jsondata["dateFlag"]=self.__getdateFlag()
        self.__jsondata["avgSpeed"]=self._getavgSpeed()
        self.__jsondata["geolations"]=self.__getgeolations()
        self.__jsondata["unqualified"]=0
        self.__jsondata["total"]=self._gettotal()
        self.__jsondata["stepNumber"]=self.__getstepNumber()
        self.__jsondata["updatetime"]=0
        self.__jsondata["pointNum"]=len(self.__punchPoints)
        self.__jsondata["endDatetime"]=self._getTime()
        self.__jsondata["key"]=self.__getkey()

    def _getTime(self):
        return int(time.time()*10**3)

    def __getsummile(self):
        return str(round(self.__totaldistance/1000,2))
    
    def setsubmitnum(self,num):
        self.__submitnum=num

    def getsubmitnum(self):
        return self.__submitnum

    def addpunchPoints(self, __newpunchPoints):
        lastdata=__newpunchPoints
        __newpunchPoints=OrderedDict()
        __newpunchPoints["lng"]=lastdata["longitude"]
        __newpunchPoints["t"]=self._getTime()
        __newpunchPoints["lat"]=lastdata["latitude"]
        if len(self.__punchPoints) == 0:
            self.__punchPoints = [__newpunchPoints]
        else:
            self.__punchPoints.append(__newpunchPoints)

    def __getpunchPoints(self):
        json_str = json.dumps(self.__punchPoints, ensure_ascii=False)
        return str(json_str)

    def getpunchPoints(self):
        return str(self.__punchPoints)
    
    def addgeolation(self,__newGeolations):
        __newGeolations["t"]=self._getTime()
        lastdata=__newGeolations
        __newGeolations = OrderedDict()
        __newGeolations["t"] = lastdata["t"]
        __newGeolations["latitude"] = lastdata["latitude"]
        __newGeolations["longitude"] = lastdata["longitude"]

        if len(self.__geolations) == 0:
            self.__geolations = [__newGeolations]
            
        else:
            self.__geolations.append(__newGeolations)
            preLocation=(self.__geolations[-2]["latitude"],self.__geolations[-2]["longitude"])
            nxtLocation=(self.__geolations[-1]["latitude"],self.__geolations[-1]["longitude"])
            self.__addDistance(geopy.distance.geodesic(preLocation,nxtLocation).m)
        
    def __addDistance(self,distance):
        self.__totaldistance += distance

    def __getdateFlag(self):
        seconds=int((self._getTime()-self.__jsondata["startDatetime"])/1000)
        minutes = seconds // 60
        remaining_seconds = seconds % 60
        # 格式化为mm'ss''的字符串
        formatted_time = "{:d}'{:02d}''".format(minutes, remaining_seconds)
        return formatted_time

    def _getavgSpeed(self):
        if self.__totaldistance==0:
            return "0'00'"
        seconds=int((self._getTime()-self.__jsondata["startDatetime"])/1000)
        speed=int(seconds/(self.__totaldistance/1000))
        minutes = speed // 60
        remaining_seconds = speed % 60
        formatted_speed = "{:d}'{:02d}''".format(minutes, remaining_seconds)
        return formatted_speed

    def __getgeolations(self):
        geodata={}
        geodata["code"]=200
        geodata["data"]={}
        geodata["data"]["postionList"]=self.__geolations
        geodata["success"]=True
        geodatastr = json.dumps(geodata, ensure_ascii=False)
        geodatastr = geodatastr.replace(" ","")
        return geodatastr

    def _gettotal(self):
        return int(self.__totaldistance)

    def __get_md5(self,str):
        if not str:
            return ""
        md5_hash = hashlib.md5()
        md5_hash.update(str.encode('utf-8'))
        return md5_hash.hexdigest()

    def __get_md5_iterations(self,oristr, iterations):
        if not oristr:
            return ""
        for _ in range(iterations):
            oristr = self.__get_md5(oristr)
        return oristr

    def __getstepNumber(self):
        return int(self.__totaldistance*1.2 + random.randint(0,10))

    def __getkey(self):
        geolationsstr=self.__getgeolations()
        a=int(len(geolationsstr)/2)
        geolationsstr=geolationsstr[0:a]
        return self.__get_md5_iterations(self.__jsondata["id"]+geolationsstr,1)

    def getjson(self):
        self.__refreshjson()
        json_str = json.dumps(self.__jsondata, ensure_ascii=False)
        json_str = json_str.replace(" ","")
        return json_str


class Sport(DataTemplate):
    xh=2208170203
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    appDevice="_22011211C_Android_13"
    userid="90f80a30-24f7-47a7-8be8-fa87c9539895"
    __nextpunchPoint=[]
    __checkpoints=[]
    __energymanagement=""
    header={
        "User-Agent": "okhttp/4.9.3",
    }
    Cookie={}
    PointNum=0
    PointCount=0
    submitNum=0

    def __init__(self,xh,appDevice,userid,energymanagement):
        self.xh=xh
        self.appDevice=appDevice
        self.userid=userid
        self.Cookie["energymanagement"]=energymanagement
        self.__energymanagement=energymanagement
        checkpointsstr = req.get(url="http://aitiyuplus.cn:8091/sports-reform/pounchPoints/getCheckInPointList",
                                 headers=self.header,
                                 cookies=self.Cookie).text
        temppoints = json.loads(checkpointsstr)["data"]
        for p in temppoints:
            points={}
            points["latitude"]=p["latitude"]
            points["longitude"]=p["longitude"]
            self.__checkpoints.append(points)

        logformat='%(asctime)s %(levelname)s: %(message)s'
        os.makedirs(LOGPATH+self.xh, exist_ok=True)
    
    def __upload(self,last=False):
        if last:
            self.setsubmitnum(self.getsubmitnum())
        else:
            self.setsubmitnum(self.getsubmitnum()+1)
        self.submitNum=self.getsubmitnum()
        uploaddata=self.getjson()
        uploaddata=json.loads(uploaddata)
        time.sleep(0.1)
        uploaddata["updatetime"] = self._getTime()
        if last:
            uploaddata["subMit"] = "0"
            self.submitNum=0
        uploaddata=json.dumps(uploaddata, ensure_ascii=False)
        uploaddata=uploaddata.replace(" ","")
        self.postData(uploaddata)

    def postData(self,data):
        headers = """\
POST /sports-reform/pounchPoints/addGeolation/add HTTP/1.1
Content-Type: application/json; charset=UTF-8
Content-Length: 794
Host: aitiyuplus.cn:8091
Connection: Keep-Alive
Accept-Encoding: gzip
Cookie: energymanagement=94349681-55f0-4f32-bf62-6bec9d5b9161
User-Agent: okhttp/4.9.3\r\n\r\n"""
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        content_length = len(data)
        headers = headers.replace("Content-Length: 794", f"Content-Length: {content_length}")
        headers = headers.replace("Cookie: energymanagement=94349681-55f0-4f32-bf62-6bec9d5b9161",
                                   f"Cookie: energymanagement={self.__energymanagement}")
        request = headers + data
        self.__writeLog(LOGPATH+self.xh+"/"+self._SportId+"/","Point "+str(self.submitNum)+" request.txt",request)
        host = "127.0.0.1" if DEBUG else "aitiyuplus.cn"
        port = 1314 if DEBUG else 8091
        self.client_socket.settimeout(10)  # 设置超时时间为10秒
        self.client_socket.connect((host, port))
        self.client_socket.send(request.encode())
        response = self.client_socket.recv(4096000)
        self.__writeLog(LOGPATH+self.xh+"/"+self._SportId+"/","Point "+str(self.submitNum)+" response.txt",response.decode("utf-8"))
        self.client_socket.close()
        return response.decode("utf-8")

    def __refreshpunchPoint(self,position):
        submitnum=self.getsubmitnum()
        if(len(self.__nextpunchPoint)==0):
            self.__nextpunchPoint=self.__checkpoints[1]
            logging.info("初始化第一个测试点成功")
            print("\n\n\n\n\n")
            return False
        else:
            nowPoint=(position["latitude"],position["longitude"])
            nextpunchPoint=(self.__nextpunchPoint["latitude"],self.__nextpunchPoint["longitude"])
            distancetopoint=geopy.distance.geodesic(nowPoint,nextpunchPoint).m
            self.__refreshScreen(NowPosition=nowPoint,distancetopoint=distancetopoint)
            if(distancetopoint<20):
                if(submitnum==0):
                    self.__nextpunchPoint=self.__checkpoints[0]
                    return True
                if(submitnum==1):
                    self.__nextpunchPoint=self.__checkpoints[2]
                    return True
                if(submitnum==2):
                    self.__nextpunchPoint=self.__checkpoints[1]
                    return True
                if(submitnum % 3 == 0):
                    self.__nextpunchPoint=self.__checkpoints[2]
                    return True
                if(submitnum % 3 == 1):
                    self.__nextpunchPoint=self.__checkpoints[0]
                    return True
                if(submitnum % 3 == 2):
                    self.__nextpunchPoint=self.__checkpoints[1]
                    return True
            else:
                return False
            
    def start(self,positiondata):
        DataTemplate.__init__(self,xh=self.xh,appDevice=self.appDevice,userid=self.userid)
        logging.info("启动跑步成功!")
        self.PointNum=len(positiondata)
        for i,position in enumerate(positiondata) :
            self.PointCount=i
            nowpunchPoint=self.__nextpunchPoint
            self.addgeolation(position)
            if(self.__refreshpunchPoint(position) == True):
                self.addpunchPoints(nowpunchPoint)
                self.__upload()
            time.sleep(2)
        self.__upload(last=True)

    def __writeLog(self,Dir,FileName,str):
        os.makedirs(Dir, exist_ok=True)
        logFile = open(Dir+FileName, "w", encoding="utf-8")
        logFile.write(str)
        # 关闭文件
        logFile.close()

    def __refreshScreen(self,NowPosition,distancetopoint):
        for i in range(5):
            if sys.platform == 'win32':
                # Windows终端ANSI转义序列开启
                sys.stdout.write('\033[F')  # 光标上移一行
                sys.stdout.write('\033[K')  # 擦除整行内容
            else:
                sys.stdout.write('\x1b[1A')  # 光标上移一行
                sys.stdout.write('\x1b[2K')  # 擦除整行内容
            sys.stdout.flush()
        total=self.PointNum - 1

        print("当前坐标： ",NowPosition,
              "\n测试点坐标：",(float(self.__nextpunchPoint["latitude"]),(float(self.__nextpunchPoint["longitude"]))),
              "\n和测试点距离：",round(distancetopoint,2))
        print("当前跑步已完成：",round((self.PointCount / total)*100,2),"%  ",
              "配速：",self._getavgSpeed(),
              "  里程数：",self._gettotal(),
              "  已上传测试点个数：",self.getsubmitnum())
        if self.PointCount == total:
            logging.debug("本次跑步配速："+str(self._getavgSpeed())+"  里程数："+str(self._gettotal())+"  打卡点数："+str(self.getsubmitnum()))
        for p in range(50):
            if (p/50) <= (self.PointCount /total):
                print("#",end="")
            else:
                print("-",end="")
        print("")
